Skip to Content

14장 전역 변수의 문제점

14-1. 변수의 생명 주기

14-1-1. 지역 변수의 생명 주기

지역 변수의 생명 주기 == 함수의 생명 주기

function foo() { var x = 'local'; console.log(x); return x; } foo(); // local console.log(x); // ReferenceError: x is not defined
  • 지역 변수 x는 foo 함수가 호출됐을 시에만 생성!

image.png

  • 변수의 생명 주기: 메모리 공간이 확보된 시점 ~ 메모리 공간이 해제되어 가용 메모리 풀에 반환되는 시점
  • 함수가 생성한 스코프에 함수 내부에서 선언된 지역 변수 등록
  • 따라서 변수는 자신이 등록된 스코프가 소멸(메모리 해제)될 때까지 유효
  • 그런데, 함수가 종료되었을 때 누군가가 스코프를 계속 참조하고 있다면? -> 스코프 생존!

스코프 생존의 결과: 함수 몸체 내부에서 선언된 지역 변수가 함수보다 오래 생존하는 경우 발생 이에 대해서는 24장 “클로저”에서 자세히 살펴보자

호이스팅 동작과 스코프 : 호이스팅 동작의 단위가 바로 스코프

  • 전역 변수의 호이스팅 -> 전역 변수의 선언이 전역 스코프의 선두로 끌어 올려진 것처럼 동작

    전역 변수는 전역 전체에서 유효!

  • 지역 변수의 호이스팅 -> 지역 변수의 선언이 지역 스코프의 선두로 끌어 올려진 것처럼 동작

    지역 변수는 함수 전체에서 유효!

var x = 'global'; function foo() { console.log(x); var x = 'local'; } foo(); // undefined console.log(x); // global
  • foo 함수 내부에서 선언된 지역 변수 x는 함수 내부에서 선언되어 undefined로 초기화

14-1-2. 전역 변수의 생명 주기

전역 변수의 생명 주기 == 전역 객체의 생명 주기

전역 객체 : 코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체

전역 객체의 프로퍼티

  • 표준 빌트인 객체
  • 환경에 따른 호스트 객체
  • var 키워드로 선언한 전역 변수와 전역 함수 이에 대해서는 21장 “빌트인 객체”에서 자세히 살펴보자

브라우저 환경에서 var 키워드로 선언한 전역 변수는 웹페이지를 닫을 때까지 유효

image.png

14-2. 전역 변수의 문제점

  1. 암묵적 결합
  • 모든 코드가 전역 변수를 참조하고 변경할 수 있음
  • 변수의 유효 범위가 크면 클수록 코드 가독성 &darr, 의도치 않은 상태 변경 위험성 &uarr
  1. 긴 생명 주기
  • 생명 주기가 긴 전역 변수는 메모리 리소스를 오랜 기간 소비함
  • 전역 변수의 상태를 변경할 수 있는 시간과 기회 &uarr
  • var 키워드의 중복 선언 허용에 의해 변수 이름이 중복될 가능성 존재 -> 의도치 않은 재할당 (전역 변수보다 생명 주기가 짧은 지역 변수는 위 문제가 발생할 가능성 낮음!)
  1. 스코프 체인 상에서 종점에 존재
  • 변수 검색 시 스코프 체인을 따라 검색하는데, 종점이면 가장 마지막에 검색됨을 의미함
  • 결국, 전역 변수의 검색 속도가 가장 느림
  • 속도 차이가 크지 않음에도, 이 차이는 분명히 존재함
  1. 네임스페이스 오염
  • 자바스크립트는 파일이 분리되어 있어도 하나의 전역 스코프를 공유함
  • 결국 다른 파일 내에 동일한 이름의 전역 변수/함수가 같은 스코프에 존재하면 예쌍치 못한 결과 발생 가능

14-3. 전역 변수의 사용을 억제하는 방법

변수의 스코프는 좁을수록 좋음

전역 변수를 꼭 사용해야 하는 경우가 아니라면 지역 변수를 사용하자!

14-3-1. 즉시 실행 함수

모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 됨

  • 그런데, 함수 내에서 선언된 변수는 애초에 지역 변수 아닌가? : var 키워드의 중복 선언 허용을 방지하기 위해 애초부터 차단하는 느낌
// 모든 코드를 IIFE로 감싸서 실행 (function () { var localVars = 10; // IIFE의 지역 변수 console.log(localVars); // 10 })(); console.log(localVars); // ReferenceError: localVars is not defined

(IIFE: 즉시 실행 함수)

  • 필자의 개인적 의견 위 예시처럼 애초에 함수의 역할로써 사용하는 것이 아니라, ‘localVars’라는 변수를 사용하고 바로 지울 수 있도록 하는 용도라 생각됨

  • 이는 함수 단원에서 얘기했던 ‘즉시 실행 함수가 함수의 재사용성이란 특성에 위배되는 것이 아닌가’ 라는 의문에도 답이 될수 있을 듯

14-3-2. 네임스페이스 객체

전역에 네임스페이스 역할을 담당할 객체를 생성, 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가

var MYAPP = {}; // 전역 네임스페이스 객체 MYAPP.name = 'Lee'; console.log(MYAPP.name); // Lee

네임스페이스 객체에 또 다른 네임스페이스 객체를 추가 -> 계층적 구성 또한 가능 (다만 네임스페이스 객체 자체가 전역 변수에 할당되어 그다지 유용하진 않음)

14-3-3. 모듈 패턴

클래스를 모방

  • 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 생성
  • 클로저를 기반으로 동작
  • 전역 변수의 억제 + 캡슐화 구현

이에 대해서는 24장 “클로저”에서 자세히 살펴보자

캡슐화: 객체의 상태를 나타내는 프로퍼티와 이를 참조하고 조작하는 동작인 메서드를 하나로 묶는 것 객체의 특정 프로퍼티나 메서드를 감출 목적 -> 정보 은닉

대부분의 객체지향 프로그래밍 언어는 접근 제한자를 사용해 공개범위를 한정할 수 있음

하지만 자바스크립트는 접근 제한자를 제공하지 않아 모듈 패턴으로 이를 대체함

var Counter = (function(){ // private 변수 var num = 0; // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환 return { increase(){ return ++num; }, decrease(){ return --num; } }; }()); // private 변수는 외부로 노출되지 않음 console.log(Counter.num); // undefined console.log(Counter.increase()); // 1 console.log(Counter.increase()); // 2 console.log(Counter.decrease()); // 1 console.log(Counter.decrease()); // 0
  • 위 예제의 즉시 실행 함수는 객체를 반환
  • 이 객체에는 외부에 노출하고 싶은 public 변수/함수를 담아 반환
  • private 멤버는 반환 객체에 추가하지 않으면 됨 이에 대해서는 24장 “클로저”에서 자세히 살펴보자

14-3-4. ES6 모듈

ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공

  • 따라서, ES6 모듈을 사용하면 더는 전역 변수를 사용할 수 없음
  • 모듈 내에서 var 키워드로 선언한 변수는 전역 변수가 아님, window 객체의 프로퍼티도 아님

모던 브라우저에서 script 태그에 type = “module” 어트리뷰트를 추가하면 로드된 자바스크립트 파일은 모듈로서 동작

파일 확장자는 mjs를 권장

<script type="module" src="lib.mjs"></script> <script type="module" src="app.mjs"></script>
  • ES6 모듈은 IE를 포함한 구형 브라우저에서는 동작하지 않음
  • 사용하더라도 트랜스파일링, 번들링이 필요함
  • 따라서, Webpack 등 모듈 번들러를 사용하는 것이 일반적 이에 대해서는 48장 “모듈”과 49장 “Babel과 Webpack을 이용한 ES6+/ES.NEXT 개발 환경 구축”에서 자세히 살펴보자

🧐 전역 변수와 스코프 개념 확인 문제

  1. 전역 변수가 가진 문제점에 대한 설명으로 가장 옳지 않은 것은 무엇인가요?

A. 긴 생명 주기는 메모리 리소스를 오랜 기간 소비하며, var의 중복 선언 허용과 결합하여 의도치 않은 재할당 위험을 높인다. B. 암묵적 결합은 모든 코드가 전역 변수를 참조하고 변경할 수 있게 하여 코드의 가독성을 낮춘다. C. 스코프 체인 상에서 종점에 존재하므로, 전역 변수는 지역 변수에 비해 변수 검색 속도가 가장 빠르다. D. 네임스페이스 오염은 파일이 분리되어도 하나의 전역 스코프를 공유하여 동일 이름의 변수/함수가 예상치 못한 결과를 발생시킬 수 있다.

정답 및 해설 보기

정답: C

해설: 전역 변수는 스코프 체인 상에서 **종점(가장 마지막)**에 존재하므로, 변수 검색 시 스코프 체인을 따라 검색할 때 가장 마지막에 검색됩니다. 따라서 검색 속도가 가장 느립니다.

  1. var 키워드로 선언된 지역 변수의 생명 주기에 대한 설명으로 옳은 것은 무엇인가요?

A. 지역 변수는 자신이 선언된 함수가 호출되기 전에 생성되어 전역 객체에 등록된다. B. 지역 변수의 생명 주기는 자신이 등록된 스코프가 소멸될 때까지 유효하며, 이는 함수의 생명 주기와 일치한다.
C. 함수가 종료되면 지역 변수는 즉시 메모리에서 해제되지만, 호이스팅에 의해 재활용될 수 있다. D. return 문이 실행되면 지역 변수가 메모리에서 해제되어 가용 메모리 풀에 반환된다.

정답 및 해설 보기

정답: B

해설: 지역 변수의 생명 주기는 함수의 생명 주기와 일치합니다. 변수는 자신이 등록된 스코프가 소멸될 때까지 유효하며, 스코프는 함수가 종료될 때 소멸됩니다. (다만, 클로저에 의해 스코프가 생존하는 예외적인 경우도 있습니다.)

  1. 다음 코드의 실행 결과와, 이 현상을 설명하는 개념이 올바르게 짝지어진 것은 무엇인가요?
var x = 'global'; function foo() { console.log(x); var x = 'local'; } foo();

A. 결과: global / 개념: 전역 변수 유효 범위
B. 결과: local / 개념: 스코프 체인 C. 결과: undefined / 개념: 지역 변수의 호이스팅
D. 결과: ReferenceError / 개념: 지역 변수 생명 주기

정답 및 해설 보기

정답: C

해설: foo 함수 내부에서 선언된 지역 변수 x의 선언이 지역 스코프의 선두로 호이스팅됩니다. 따라서 console.log(x) 시점에 이미 var x가 선언되었지만, 값 할당(‘local’) 이전에 실행되므로 변수 x는 undefined로 초기화된 상태로 출력됩니다.

  1. 전역 변수의 사용을 억제하는 방법 중, **즉시 실행 함수(IIFE)**를 사용하는 이유로 가장 적절한 것은 무엇인가요?

A. 즉시 실행 함수는 함수의 재사용성을 극대화하기 위해 사용된다. B. 전역 객체에 네임스페이스 역할을 담당할 객체를 생성하기 위함이다. C. 모든 코드를 지역 스코프 안에 감싸 var 변수의 전역 노출을 막아 변수 이름 충돌을 방지하기 위함이다. D. 클로저를 기반으로 동작하며, 객체의 프로퍼티와 메서드를 묶어 캡슐화를 구현하기 위함이다.

정답 및 해설 보기

정답: C

해설: IIFE를 사용하는 주된 목적은 모든 코드를 IIFE의 지역 변수로 만들어, 특히 var 키워드가 가진 함수 레벨 스코프 특성으로 인해 발생하는 전역 변수 오염 및 중복 선언을 방지하는 것입니다.

  1. module 패턴을 사용하여 클로저 기반의 캡슐화를 구현한 다음 코드에 대한 설명으로 옳은 것은 무엇인가요?
var Counter = (function(){ var num = 0; // (가) return { increase(){ return ++num; }, decrease(){ return --num; } }; }()); console.log(Counter.num); // undefined

A. Counter.num이 undefined인 이유는 num 변수가 전역 변수이기 때문이다.
B. 모듈 패턴은 자바스크립트의 접근 제한자(Access Modifier)를 사용하여 정보 은닉을 구현한다. C. (가)에서 선언된 num은 private 변수 역할을 하며, 이는 반환되는 객체에 포함되지 않아 외부로 노출되지 않는다. D. Counter 변수는 즉시 실행 함수가 반환한 함수를 참조하며, 이는 재사용성이 없다는 단점이 있다.

정답 및 해설 보기

정답: C

해설: 모듈 패턴은 관련 변수와 함수를 IIFE로 감싸서 생성합니다. 클로저를 기반으로 동작하며, IIFE 내부에서 선언된 num 변수는 private 변수 역할을 하여 외부로 노출되지 않습니다.

A. num은 IIFE의 지역 변수이며, 외부로 노출되지 않아 undefined가 출력됩니다.

B. 자바스크립트는 접근 제한자를 제공하지 않아 모듈 패턴으로 캡슐화를 대체합니다.

D. Counter 변수는 즉시 실행 함수가 반환한 객체를 참조합니다.

Last updated on